#include "BlockSorting.h"

//devuelve el caracter siguiente de una cadena de caracteres(fila de la seudomatriz)
unsigned char obtenerSiguiente(unsigned char *s,int offset,int tamanio,int caracteresSiguientes){
    int aux = tamanio -1 - offset;
    if(caracteresSiguientes > aux)
        return s[caracteresSiguientes - aux -1];
    else
        return s[offset + caracteresSiguientes];
}



int compararRegistros(unsigned char* s,int offset1,int offset2, int tamanio,int caracteresSiguientes,int op){
    if ( offset1 == offset2) return 0;//pues son iguales y con esto se evita un ciclo infinito

    unsigned char aux1 = obtenerSiguiente(s,offset1,tamanio,caracteresSiguientes);
    unsigned char aux2 = obtenerSiguiente(s,offset2,tamanio,caracteresSiguientes);
    //compara "profundamente" dos cadenas de caracteres(filas de la seudomatriz)
    if(op==BlockSortingC){
        if(aux1>aux2)
            return 1;
        else if(aux1<aux2)
                return -1;
            else
                return compararRegistros(s,offset1,offset2,tamanio,caracteresSiguientes+1,op);
    }
    else{//la comparacion incluye la posicion del char, importante hacerlo
        if(aux1>aux2)
            return 1;
        else if(aux1<aux2)
                return -1;
            else{
                if(offset1<offset2) return -1;
                else return 1;
            }
    }
}

void swap(int *o1,int *o2){
    int temp = *o1;
    *o1 = *o2;
    *o2 = temp;
}

void quickSort (unsigned char *s, int* v,int izquierda, int derecha,int tamanio, int op){
     register int i, j;
     int pivote;
     i = izquierda;
     j = derecha;
     pivote = v[(izquierda + derecha) / 2];

     do {
       while (( compararRegistros( s, v[i], pivote, tamanio, 0 ,op) < 0 ) && ( i < derecha )) i++;
       while (( compararRegistros( s, v[j], pivote, tamanio, 0 ,op) > 0 ) && ( j > izquierda )) j--;

        if(!(i > j)){
            if(i < j)
                swap(v + i,v + j);

            i++; j--;
        }
     } while ( i < j ) ;

     if ( izquierda < j ) quickSort( s,v, izquierda, j ,tamanio,op);
     if ( i < derecha ) quickSort(s,v, i, derecha ,tamanio,op);
}

unsigned char* obtenerSalida(unsigned char *entrada,int *posiciones,int tamanio){
    int i;
    unsigned char* salida=malloc(sizeof(unsigned char)*tamanio);
    for(i=0;i<tamanio;i++)
       salida[i]=obtenerSiguiente(entrada,posiciones[i],tamanio,tamanio-1);

    return salida;
}
///

void codificarBlockSorting(unsigned char* entrada,unsigned char**salida,short int* indice,int tamanho){
    int* vectorDePunteros=malloc(tamanho*sizeof(int));

    if(vectorDePunteros!= NULL){
       inicializarVectorPunteros(vectorDePunteros,tamanho);
       quickSort(entrada,vectorDePunteros,0,tamanho-1,tamanho,BlockSortingC);

       *salida= obtenerSalida(entrada,vectorDePunteros,tamanho);
       *indice=obtenerFila(vectorDePunteros,tamanho);
        free(vectorDePunteros);
    }
}

void inicializarVectorPunteros(int* entrada, int size){
    int i;
    for(i=0;i<size;i++)
        entrada[i]=i;
}




unsigned char* decodificarBlockSorting(unsigned char* entrada,int indice,int tamanio){
    int *vectorT = malloc(sizeof(int)*tamanio);
    unsigned char* salida = malloc(sizeof(unsigned char)*tamanio);

    inicializarVectorPunteros(vectorT,tamanio);
    quickSort(entrada,vectorT,0,tamanio-1,tamanio,BlockSortingD);
    int i=0;
    for(;i<tamanio;i++){
        indice=vectorT[indice];
        salida[i]=entrada[indice];
    }
    return salida;
}

int obtenerFila(int* posiciones,int tamanio){
	int i=0;
	while(i<tamanio){
		if(posiciones[i]==0)
			return i;
		i++;
	}
	return -1;
}

void imprimirVectorDeChar(unsigned char* entrada, int tamanio){
    int i=0;
    for(;i<tamanio;i++)
        printf("%c",entrada[i]);
}
